from typing import Union, List, Optional
from datetime import date
from sqlalchemy.ext.asyncio import AsyncSession
from fastapi import HTTPException, Response

from module_admin.entity.vo.common_vo import CrudResponseModel
from module_kylin.dao.future_account_daily_dao import FutureAccountDailyDao
from module_kylin.entity.vo.future_account_daily_vo import (
    FutureAccountDailyModel,
    FutureAccountDailyPageQueryModel,
    DeleteFutureAccountDailyModel,
)
from utils.common_util import CamelCaseUtil
from utils.excel_util import ExcelUtil
from utils.log_util import logger


class FutureAccountDailyService:
    """
    期货账户资金日报业务逻辑层
    """

    @classmethod
    async def add_account_daily(cls, db: AsyncSession, account_daily: FutureAccountDailyModel):
        """
        新增期货账户资金日报

        :param db: 数据库会话
        :param account_daily: 账户资金日报信息
        :return: 操作结果
        """
        try:
            # 验证必填字段
            if not account_daily.account_code:
                raise HTTPException(status_code=400, detail="账户代码不能为空")
            if not account_daily.settlement_date:
                raise HTTPException(status_code=400, detail="结算日期不能为空")

            # 检查是否已存在相同结算日期和账户代码的记录
            existing_daily = await FutureAccountDailyDao.get_account_daily_by_date_and_account(
                db, account_daily.settlement_date, account_daily.account_code
            )
            if existing_daily:
                raise HTTPException(status_code=400, detail=f"账户{account_daily.account_code}在{account_daily.settlement_date}的记录已存在")

            # 添加记录
            await FutureAccountDailyDao.add_account_daily(db, account_daily)
            await db.commit()

            return CrudResponseModel(is_success=True, message='新增成功')
        except HTTPException as e:
            await db.rollback()
            raise e
        except Exception as e:
            await db.rollback()
            raise HTTPException(status_code=500, detail=str(e))

    @classmethod
    async def get_account_daily_detail(cls, db: AsyncSession, daily_id: int):
        """
        获取期货账户资金日报详情

        :param db: 数据库会话
        :param daily_id: 账户资金日报id
        :return: 账户资金日报详情
        """
        try:
            # 获取账户资金日报详情
            account_daily_detail = await FutureAccountDailyDao.get_account_daily_by_id(db, daily_id)

            if not account_daily_detail:
                raise HTTPException(status_code=404, detail=f"期货账户资金日报{daily_id}不存在")

            # 使用FutureAccountDailyModel和CamelCaseUtil转换为驼峰命名法
            return FutureAccountDailyModel(**CamelCaseUtil.transform_result(account_daily_detail))
        except HTTPException as e:
            raise e
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))

    @classmethod
    async def get_account_daily_list(cls, db: AsyncSession, query_model: FutureAccountDailyPageQueryModel, 
                                   is_page: bool = True):
        """
        获取期货账户资金日报列表

        :param db: 数据库会话
        :param query_model: 查询参数
        :param is_page: 是否开启分页
        :return: 分页后的期货账户资金日报列表
        """
        try:
            # 获取期货账户资金日报列表
            account_daily_page = await FutureAccountDailyDao.get_account_daily_list(db, query_model, is_page)

            # 返回分页结果
            if is_page:
                return account_daily_page
            return account_daily_page
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))

    @classmethod
    async def update_account_daily(cls, db: AsyncSession, daily_id: int, account_daily: FutureAccountDailyModel):
        """
        更新期货账户资金日报

        :param db: 数据库会话
        :param daily_id: 账户资金日报id
        :param account_daily: 账户资金日报信息
        :return: 操作结果
        """
        try:
            # 检查记录是否存在
            existing_daily = await FutureAccountDailyDao.get_account_daily_by_id(db, daily_id)
            if not existing_daily:
                raise HTTPException(status_code=404, detail=f"期货账户资金日报{daily_id}不存在")

            # 检查是否存在冲突的记录
            if account_daily.settlement_date and account_daily.account_code:
                conflict_daily = await FutureAccountDailyDao.get_account_daily_by_date_and_account(
                    db, account_daily.settlement_date, account_daily.account_code
                )
                if conflict_daily and conflict_daily.get('id') != daily_id:
                    raise HTTPException(status_code=400, detail=f"账户{account_daily.account_code}在{account_daily.settlement_date}的记录已存在")

            # 更新记录
            await FutureAccountDailyDao.update_account_daily(db, daily_id, account_daily)
            await db.commit()

            return CrudResponseModel(is_success=True, message='更新成功')
        except HTTPException as e:
            await db.rollback()
            raise e
        except Exception as e:
            await db.rollback()
            raise HTTPException(status_code=500, detail=str(e))

    @classmethod
    async def delete_account_daily(cls, db: AsyncSession, delete_model: DeleteFutureAccountDailyModel):
        """
        删除期货账户资金日报

        :param db: 数据库会话
        :param delete_model: 删除参数
        :return: 操作结果
        """
        try:
            # 检查期货账户资金日报是否存在
            for daily_id in delete_model.ids:
                existing_daily = await FutureAccountDailyDao.get_account_daily_by_id(db, daily_id)
                if not existing_daily:
                    raise HTTPException(status_code=404, detail=f"期货账户资金日报{daily_id}不存在")

            # 批量删除期货账户资金日报
            await FutureAccountDailyDao.batch_delete_account_daily(db, delete_model.ids)
            await db.commit()

            return CrudResponseModel(is_success=True, message='删除成功')
        except HTTPException as e:
            await db.rollback()
            raise e
        except Exception as e:
            await db.rollback()
            raise HTTPException(status_code=500, detail=str(e))
            
    @classmethod
    async def delete_account_daily_by_date_and_account(cls, db: AsyncSession, settlement_date: date, account_code: str):
        """
        根据结算日期和账户代码删除期货账户资金日报

        :param db: 数据库会话
        :param settlement_date: 结算日期
        :param account_code: 账户代码
        :return: 是否有记录被删除
        """
        try:
            deleted = await FutureAccountDailyDao.delete_account_daily_by_date_and_account(db, settlement_date, account_code)
            await db.commit()
            return deleted
        except Exception as e:
            await db.rollback()
            raise HTTPException(status_code=500, detail=f"删除期货账户资金日报失败: {str(e)}")



    @classmethod
    async def export_account_daily(cls, db: AsyncSession, query_model: FutureAccountDailyPageQueryModel):
        """
        导出期货账户资金日报

        :param db: 数据库会话
        :param query_model: 查询参数
        :return: Excel响应
        """
        # 获取所有数据（不分页）
        account_daily_list = await FutureAccountDailyDao.get_account_daily_list(db, query_model, is_page=False)
        
        # 准备导出数据
        export_data = []
        for item in account_daily_list:
            export_data.append({
                '账户代码': item.get('account_code'),
                '结算日期': item.get('settlement_date').strftime('%Y-%m-%d') if item.get('settlement_date') else '',
                '期初权益(逐日盯市)': item.get('previous_balance_day'),
                '期初权益(逐笔对冲)': item.get('previous_balance_trade'),
                '当日存取': item.get('daily_deposit_withdrawal'),
                '当日盈亏': item.get('daily_profit_day'),
                '当日余额': item.get('daily_balance_day'),
                '总盈亏': item.get('close_profit_trade'),
                '当日交易余额': item.get('daily_balance_trade'),
                '浮动盈亏': item.get('float_profit_trade'),
                '当日费用': item.get('daily_fee'),
                '期末权益': item.get('equity'),
                '保证金': item.get('margin_used'),
                '可用资金': item.get('available_funds'),
                '风险度': item.get('risk_ratio')
            })
        
        # 生成Excel文件
        excel_util = ExcelUtil()
        excel_data = excel_util.create_excel(export_data, '期货账户资金日报')
        
        # 返回响应
        return Response(
            content=excel_data,
            media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            headers={
                'Content-Disposition': f'attachment; filename=期货账户资金日报_{date.today().strftime("%Y%m%d")}.xlsx'
            }
        )